// 题目精炼说明
// 给定一个 n 行 m 列的网格，. 表示荒地，# 表示杂物。
// 一块荒地可以被开垦，当且仅当它上下左右四个方向的格子都不是杂物。
// 你可以选择至多一个位置清除杂物（把一个 # 变成 .）。
// 问最多能开垦多少块荒地。

// 代码逻辑简述
// 统计原本能直接开垦的荒地数（四周没有杂物）。
// 统计每个杂物格子：如果清除它，能让多少荒地变得可开垦（包括自己）。
// 答案为：原本能开垦的 + 清除一个杂物后能多开的最大数。

#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
char mat[N][N];      // 存储网格
int a[N][N];         // 记录每个位置清除后能多开垦的荒地数
const int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右四个方向

int main() {
    int n, m, ans = 0;
    scanf("%d%d", &n, &m);
    assert(1 <= n && n <= 1000);
    assert(1 <= m && m <= 1000);

    // 读入网格
    for (int i = 1; i <= n; i ++)
        scanf("%s", mat[i] + 1);

    // 遍历每个格子
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++) {
            int num = 0, p = -1;
            // 统计四周有几个杂物，并记录最后一个方向
            for (int k = 0; k < 4; k ++)
                if (mat[i + d[k][0]][j + d[k][1]] == '#')
                    num ++, p = k;
            // 如果当前位置是荒地，且四周只有一个杂物
            if (mat[i][j] == '.' && num == 1)
                a[i + d[p][0]][j + d[p][1]] ++;
            // 如果当前位置是荒地，且四周没有杂物，可以直接开垦
            else if (mat[i][j] == '.' && num == 0)
                ans ++;
            // 如果当前位置是杂物，且四周没有杂物，清除后自己也能开垦
            else if (mat[i][j] == '#' && num == 0)
                a[i][j] ++;
        }

    int mx = 0;
    // 找出清除一个杂物后，能多开垦的最大数量
    for (int i = 1; i <= n; i ++)
        for (int j = 0; j <= m; j ++)
            mx = max(mx, a[i][j]);

    cout << ans + mx << endl; // 总开垦数=原本能开垦的+清除一个杂物后能多开的最大数
    return 0;
}